use std::any::{Any, TypeId};
use std::collections::HashMap;
use std::str::FromStr;
use serde::{Deserialize, Serialize};
use crate::business::websocket::dto::common_dto::ExceptionResp;

const SPLIT: &str = " ";
const NEWLINE: &str = "\r\n";

#[derive(Debug)]
pub struct RpcData<T: Serialize + for<'de> Deserialize<'de> + 'static> {
    pub path: String,
    pub version: u32,
    pub status: i32,
    pub ext_data_map: HashMap<String, String>,
    pub data: Option<Result<T, ExceptionResp>>,
}

impl<T: Serialize + for<'de> Deserialize<'de> + 'static> RpcData<T> {

    pub fn new(path: String, data: T, seq: String) -> Self {
        let mut ext_data_map = HashMap::new();
        ext_data_map.insert("localSeq".to_string(), String::from(seq));

        let type_id = data.type_id();

        let mut status = 100;
        if type_id == TypeId::of::<ExceptionResp>() {
            status = -1;
        }
        RpcData {
            path,
            version: 1,
            status: 0,
            ext_data_map,
            data: Some(Ok(data)),
        }

    }

    pub fn response(path: String, data: T, seq: String) -> Self {
        let mut ext_data_map = HashMap::new();
        ext_data_map.insert("localSeq".to_string(), String::from(seq));
        RpcData {
            path,
            version: 1,
            status: 10,
            ext_data_map,
            data: Some(Ok(data)),
        }
    }

    pub fn local_seq(&self) -> String {
        let local_seq = self.ext_data_map.get("localSeq").unwrap();
        local_seq.clone()
    }
}

impl<T: Serialize + for<'de> Deserialize<'de>> From<String> for RpcData<T> {
    fn from(value: String) -> Self {
        let index = value.find(NEWLINE).unwrap_or(value.len());
        let (head_str, content) = value.split_at(index);
        log::info!("head_str: {}", head_str);
        log::info!("content_str: {}", content);

        let mut pattern = String::from(NEWLINE);
        pattern.push_str(NEWLINE);
        let second_index = content.find(&pattern).unwrap_or(0);

        let mut ext_data_str = "";
        let mut data_str = "";

        if second_index > 2 {
            (ext_data_str, data_str) = content.split_at(second_index);
        }

        log::info!("ext_data_str: {}", ext_data_str);
        log::info!("data_str: {}", data_str);

        ext_data_str = ext_data_str.trim();
        data_str = data_str.trim();
        
        let head_list = head_str.split(SPLIT).collect::<Vec<&str>>();
        let path = head_list[0].to_string();
        let version = u32::from_str(head_list[1]).unwrap();
        let status = i32::from_str(head_list[2]).unwrap();

        let mut ext_data_map = HashMap::new();
        if ext_data_str != "" {
            let _ = ext_data_str.split(NEWLINE).map(|kv_str| {
                let k_v = kv_str.split(SPLIT).collect::<Vec<&str>>();
                ext_data_map.insert(k_v[0].to_string(), k_v[1].to_string());
            });
        }
        if status < 0 {
            let data: ExceptionResp = serde_json::from_str(data_str).unwrap();
            RpcData {
                path,
                version,
                status,
                ext_data_map: HashMap::new(),
                data: Some(Err(data)),
            }
        } else {
            let data: T = serde_json::from_str(data_str).unwrap();
            RpcData {
                path,
                version,
                status,
                ext_data_map: HashMap::new(),
                data: Some(Ok(data)),
            }
        }
        
    }
}

impl<T: Serialize + for<'de> Deserialize<'de>> Into<String> for RpcData<T> {
    fn into(self) -> String {
        let mut result = String::new();
        result.push_str(self.path.as_str());
        result.push_str(SPLIT);
        result.push_str(self.version.to_string().as_str());
        result.push_str(SPLIT);
        result.push_str(self.status.to_string().as_str());
        result.push_str(NEWLINE);
        self.ext_data_map.iter().for_each(|(k, v)| {
            result.push_str(k);
            result.push_str(":");
            result.push_str(v.as_str());
            result.push_str(NEWLINE);
        });
        let data_str = if let Some(data) = &self.data {
            match data {
                Ok(t) => {
                    serde_json::to_string(t).unwrap()
                }
                Err(e) => {
                    serde_json::to_string(e).unwrap()
                }
            }
            
        } else {
            "{}".to_string()
        };
        result.push_str(NEWLINE);
        result.push_str(data_str.as_str());
        result
    }
}

#[derive(Debug)]
pub struct ReceiveDataParse {
    pub path: String,
    pub version: u32,
    pub status: i32,
    pub ext_data_map: HashMap<String, String>,
    pub data: Option<String>,
}

#[derive(Debug)]
pub struct RpcHeader {
    pub path: String,
    pub version: u32,
    pub status: i32,
    pub ext_data_map: HashMap<String, String>,
}

impl RpcHeader {

    pub fn local_seq(&self) -> String {
        let local_seq = self.ext_data_map.get("localSeq").unwrap();
        local_seq.clone()
    }

}

pub fn parse_to_header(value: String) -> (RpcHeader, String) {
    let index = value.find(NEWLINE).unwrap_or(value.len());
    let (head_str, content) = value.split_at(index);
    log::info!("head_str: {}", head_str);
    // log::info!("content_str: {}", content);

    let mut pattern = String::from(NEWLINE);
    pattern.push_str(NEWLINE);
    let second_index = content.find(&pattern).unwrap_or(0);

    let mut ext_data_str = "";
    let mut data_str = "";

    if second_index > 2 {
        (ext_data_str, data_str) = content.split_at(second_index);
    }

    log::info!("ext_data_str: {}", ext_data_str);
    log::info!("data_str: {}", data_str);

    ext_data_str = ext_data_str.trim();
    data_str = data_str.trim();

    log::info!("data_str3333333333333333333: {}", &data_str);

    let head_list = head_str.split(SPLIT).collect::<Vec<&str>>();
    let path = head_list[0].to_string();
    let version = u32::from_str(head_list[1]).unwrap();
    let status = i32::from_str(head_list[2]).unwrap();

    let mut ext_data_map = HashMap::new();
    if ext_data_str != "" {
        log::info!("ext_data str: {}", ext_data_str);
        ext_data_str.split(NEWLINE).for_each(|kv_str| {
            log::info!("ext_data kv_str: {}", kv_str);
            let k_v = kv_str.split(":").collect::<Vec<&str>>();
            ext_data_map.insert(k_v[0].to_string(), k_v[1].to_string());
        });
    }

    log::info!("ext_data: {:?}", &ext_data_map);
    let rpc_header = RpcHeader {
        path,
        version,
        status,
        ext_data_map,
    };
    (rpc_header, data_str.to_string())
}

impl ReceiveDataParse {
    pub fn parse(value: String) -> Self {
        let (rpc_header, data_str) = parse_to_header(value);
        ReceiveDataParse {
            path: rpc_header.path,
            version: rpc_header.version,
            status: rpc_header.status,
            ext_data_map: rpc_header.ext_data_map,
            data: Some(data_str.to_string()),
        }
    }

    pub fn local_seq(&self) -> String {
        self.ext_data_map.get("localSeq").unwrap().clone()
    }
}

impl <T: Serialize + for<'de> Deserialize<'de>> Into<RpcData<T>> for ReceiveDataParse {
    fn into(self) -> RpcData<T> {
        let str = self.data.unwrap();
        log::info!("parse data: {:?}", str);
        if self.status < 0 { // error
            log::info!("parse error, status: {}, {}", self.status, str);
            let exception_resp: ExceptionResp = serde_json::from_str(str.as_str()).unwrap();
            return RpcData {
                path: self.path,
                version: self.version,
                status: self.status,
                ext_data_map: self.ext_data_map,
                data: Some(Err(exception_resp)),
            };
        }
        let data: T = serde_json::from_str(&str).unwrap();
        RpcData {
            path: self.path,
            version: self.version,
            status: self.status,
            ext_data_map: self.ext_data_map,
            data: Some(Ok(data)),
        }
    }
}


pub fn decode_to_data<T: Serialize + for<'de> Deserialize<'de>>(rpc_header: &RpcHeader, data: String) -> Result<T, ExceptionResp> {
    log::info!("parse data: {:?}", data);
    if rpc_header.status < 0 { // error
        log::info!("parse error, status: {}, {}", rpc_header.status, data);
        let exception_resp: ExceptionResp = serde_json::from_str(&data).unwrap();
        return Err(exception_resp);
    }
    let data: T = serde_json::from_str(&data).unwrap();
    Ok(data)
}